package com.kun.video.util;

import cn.hutool.core.collection.ListUtil;
import cn.hutool.core.util.ReflectUtil;
import cn.hutool.core.util.StrUtil;
import com.kun.video.exception.BizException;
import io.github.classgraph.*;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.lang.ref.Reference;
import java.lang.ref.ReferenceQueue;
import java.lang.ref.SoftReference;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;

/**
 * 基于ClassGraph的类扫描与反射工具类，提供注解扫描、依赖分析、安全实例化等功能。
 * 支持全局缓存和内存敏感型软引用缓存，优化高频反射操作的性能。
 *
 * @author gzc
 * @since 2025/2/2
 **/
public class ClassGraphUtil {
    private static final Logger log = LoggerFactory.getLogger(ClassGraphUtil.class);

    /**
     * 构造函数缓存（使用软引用避免内存泄漏）
     */
    private static final Map<String, SoftReference<Constructor<?>>> CONSTRUCTOR_CACHE = new ConcurrentHashMap<>(128);
    /**
     * 引用队列用于清理失效的软引用
     */
    private static final ReferenceQueue<Constructor<?>> REF_QUEUE = new ReferenceQueue<>();
    /**
     * 默认扫描的基础包路径
     */
    public static final String BASE_PACKAGE_PATH = "com.kun";
    /**
     * 全局扫描结果
     */
    private static volatile ScanResult globalScanResult;
    /**
     * 性能监控数据
     */
    private static long totalScanTime = 0;
    private static int scanCount = 0;

    static {
        cleanStaleCacheEntries();
        initializeLazyGlobalScan(BASE_PACKAGE_PATH);
    }

    /**
     * 清理失效的缓存条目
     */
    private static void cleanStaleCacheEntries() {
        Reference<? extends Constructor<?>> ref;
        while ((ref = REF_QUEUE.poll()) != null) {
            Reference<? extends Constructor<?>> finalRef = ref;
            CONSTRUCTOR_CACHE.entrySet().removeIf(entry ->
                    entry.getValue() == finalRef
            );
        }
    }

    /**
     * 重置全局扫描结果并重新初始化
     *
     * @param packagePaths 需要扫描的包路径列表
     */
    public static void setGlobalScanResult(String... packagePaths) {
        globalScanResult = null;
        initializeLazyGlobalScan(packagePaths);
    }

    /**
     * 重置全局扫描结果并重新初始化
     *
     * @param scanResult 扫描结果
     */
    public static void setGlobalScanResult(ScanResult scanResult) {
        globalScanResult = scanResult;
    }

    /**
     * 创建ClassGraph扫描器实例
     *
     * @param packagePaths 目标包路径
     * @return 预配置的ClassGraph实例
     */
    private static ClassGraph createClassGraph(String... packagePaths) {
        return new ClassGraph()
                .enableClassInfo()
                .enableAnnotationInfo()
                .acceptPackages(packagePaths)
                .disableDirScanning()          // 禁用目录扫描提升性能
                .ignoreParentClassLoaders();   // 避免父类加载器干扰
    }

    /**
     * 延迟初始化全局扫描结果（双重检查锁保证线程安全）
     *
     * @param packagePaths 目标包路径
     */
    private static void initializeLazyGlobalScan(String... packagePaths) {
        if (globalScanResult == null) {
            synchronized (ClassGraphUtil.class) {
                if (globalScanResult == null) {
                    long start = System.currentTimeMillis();
                    log.info("Initializing optimized global scan for packages: {}", Arrays.toString(packagePaths));

                    globalScanResult = createClassGraph(packagePaths).scan();

                    long cost = System.currentTimeMillis() - start;
                    totalScanTime += cost;
                    scanCount++;
                    log.info("Global scan completed in {} ms (Avg: {} ms)",
                            cost, scanCount > 0 ? totalScanTime / scanCount : 0);
                }
            }
        }
    }

    public static Class<?> forName(String className) {
        try {
            if (StrUtil.isNotBlank(className)) {
                return Class.forName(className);
            }
        } catch (ClassNotFoundException e) {
            throw new BizException("找不到类 -> " + className);
        }
        return null;
    }

    /**
     * 创建指定类的实例（支持缓存和自动回收）
     *
     * @param className 目标类的全限定名
     * @return 类实例
     * @throws BizException 当类不存在或实例化失败时抛出
     */
    public static Object newInstance(String className) {
        cleanStaleCacheEntries();

        try {
            SoftReference<Constructor<?>> ref = CONSTRUCTOR_CACHE.computeIfAbsent(className, key -> {
                try {
                    Constructor<?> constructor = Class.forName(key).getConstructor();
                    return new SoftReference<>(constructor, REF_QUEUE);
                } catch (ClassNotFoundException e) {
                    throw new BizException("Class not found: " + key, e);
                } catch (NoSuchMethodException e) {
                    throw new BizException("Default constructor not found: " + key, e);
                }
            });

            Constructor<?> constructor = ref.get();
            if (constructor == null) {
                CONSTRUCTOR_CACHE.remove(className);
                // 递归重试
                return newInstance(className);
            }
            return constructor.newInstance();
        } catch (ReflectiveOperationException e) {
            throw new BizException(StrUtil.format("Instance creation failed for [{}]", className), e);
        }
    }

    /**
     * 类型安全实例化（泛型支持）
     *
     * @param clazz 目标类的Class对象
     * @return 类型化实例
     */
    @SuppressWarnings("unchecked")
    public static <T> T newInstance(Class<T> clazz) {
        if (clazz == null) {
            return null;
        }
        return (T) newInstance(clazz.getName());
    }

    /**
     * 查找包含指定注解的类
     *
     * @param annotationClass 目标注解类型
     * @return 符合条件的类全限定名列表
     */
    public static List<String> findAnnotated(Class<?> annotationClass) {
        return findAnnotated(annotationClass, new HashMap<>(1));
    }

    /**
     * 查找包含指定注解且属性匹配的类
     *
     * @param annotationClass      目标注解类型
     * @param annotationAttributes 注解属性键值对
     * @return 符合条件的类全限定名列表
     */
    public static List<String> findAnnotated(Class<?> annotationClass,
                                             Map<String, String> annotationAttributes) {
        return globalScanResult.getClassesWithAnnotation(annotationClass.getName())
                .stream()
                .filter(classInfo -> matchAnnotationAttributes(classInfo, annotationClass, annotationAttributes))
                .map(ClassInfo::getName)
                .toList();
    }

    /**
     * 在指定包路径下查找包含注解的类
     *
     * @param packagePaths 限定扫描的包路径
     */
    public static List<String> findAnnotated(Class<?> annotationClass,
                                             Map<String, String> annotationAttributes,
                                             String... packagePaths) {
        try (ScanResult scanResult = createClassGraph(packagePaths).scan()) {
            return scanResult.getClassesWithAnnotation(annotationClass.getName())
                    .stream()
                    .filter(classInfo -> matchAnnotationAttributes(classInfo, annotationClass, annotationAttributes))
                    .map(ClassInfo::getName)
                    .toList();
        }
    }

    /**
     * 查找实现指定接口的类
     *
     * @param interfaceClass 目标接口
     * @return 实现类的全限定名列表
     */
    public static List<String> findImplement(Class<?> interfaceClass) {
        return globalScanResult.getClassesImplementing(interfaceClass)
                .stream()
                .map(ClassInfo::getName)
                .toList();
    }

    /**
     * 在指定包路径下查找接口实现类
     *
     * @param packagePaths 限定扫描的包路径
     */
    public static List<String> findImplement(Class<?> interfaceClass, String... packagePaths) {
        try (ScanResult result = createClassGraph(packagePaths).scan()) {
            return result.getClassesImplementing(interfaceClass)
                    .stream()
                    .map(ClassInfo::getName)
                    .toList();
        }
    }

    /**
     * 查找继承指定父类的子类
     *
     * @param superClass 目标父类
     * @return 子类的全限定名列表
     */
    public static List<String> findExtend(Class<?> superClass) {
        return globalScanResult.getSubclasses(superClass)
                .stream()
                .map(ClassInfo::getName)
                .toList();
    }

    /**
     * 在指定包路径下查找子类
     *
     * @param packagePaths 限定扫描的包路径
     */
    public static List<String> findExtend(Class<?> superClass, String... packagePaths) {
        try (ScanResult result = createClassGraph(packagePaths).scan()) {
            return result.getSubclasses(superClass)
                    .stream()
                    .map(ClassInfo::getName)
                    .toList();
        }
    }

    /**
     * 查找指定类的直接依赖类
     *
     * @param targetClass 目标类
     * @return 依赖类的全限定名列表
     * @throws IllegalArgumentException 当类不存在时抛出
     */
    public static List<String> findDependencies(Class<?> targetClass) {
        ClassInfo classInfo = globalScanResult.getClassInfo(targetClass.getName());
        if (classInfo == null) {
            throw new IllegalArgumentException("Class not found: " + targetClass);
        }
        return classInfo.getClassDependencies().stream()
                .map(ClassInfo::getName)
                .toList();
    }

    /**
     * 在指定包路径下查找类依赖
     *
     * @param packagePaths 限定扫描的包路径
     */
    public static List<String> findDependencies(Class<?> targetClass, String... packagePaths) {
        try (ScanResult result = createClassGraph(packagePaths).scan()) {
            ClassInfo classInfo = result.getClassInfo(targetClass.getName());
            if (classInfo == null) {
                throw new IllegalArgumentException("Class not found: " + targetClass);
            }
            return classInfo.getClassDependencies().stream()
                    .map(ClassInfo::getName)
                    .toList();
        }
    }

    public static List<Field> getFieldList(Class<?> clazz) {
        if (clazz == null) {
            return new ArrayList<>(0);
        }
        Field[] fields = clazz.getDeclaredFields();
        String clazzName = clazz.getName();
        int indexOf = clazzName.indexOf("$");
        if (indexOf > 1) {
            String substring = clazzName.substring(0, indexOf);
            fields = ReflectUtil.getFields(forName(substring));
        }
        return ListUtil.toList(fields);
    }

    /**
     * 获取类的字段信息（类型+名称）
     *
     * @param targetClass 目标类
     * @return 字段描述列表，格式："Type Name"
     */
    public static List<String> findFields(Class<?> targetClass) {
        ClassInfo classInfo = globalScanResult.getClassInfo(targetClass.getName());
        if (classInfo == null) {
            throw new IllegalArgumentException("Class not found: " + targetClass);
        }
        return classInfo.getFieldInfo().stream()
                .map(fieldInfo -> fieldInfo.getTypeSignature() + " " + fieldInfo.getName())
                .toList();
    }

    /**
     * 在指定包路径下获取字段信息
     */
    public static List<String> findFields(Class<?> targetClass, String... packagePaths) {
        try (ScanResult result = createClassGraph(packagePaths).scan()) {
            ClassInfo classInfo = result.getClassInfo(targetClass.getName());
            if (classInfo == null) {
                throw new IllegalArgumentException("Class not found: " + targetClass);
            }
            return classInfo.getFieldInfo().stream()
                    .map(fieldInfo -> fieldInfo.getTypeSignature() + " " + fieldInfo.getName())
                    .toList();
        }
    }

    /**
     * 查找包含指定方法的类
     *
     * @param methodName     方法名
     * @param parameterTypes 方法参数类型列表
     * @return 符合条件的类全限定名列表
     */
    public static List<String> findMethods(String methodName, Class<?>... parameterTypes) {
        String[] parameterTypeNames = Arrays.stream(parameterTypes)
                .map(Class::getName)
                .toArray(String[]::new);

        return globalScanResult.getAllClasses().stream()
                .filter(classInfo -> containsMatchingMethod(classInfo, methodName, parameterTypeNames))
                .map(ClassInfo::getName)
                .collect(Collectors.toList());
    }

    /**
     * 在指定包路径下查找方法
     */
    public static List<String> findMethods(String[] packagePaths, String methodName, Class<?>... parameterTypes) {
        try (ScanResult result = createClassGraph(packagePaths).scan()) {
            String[] parameterTypeNames = Arrays.stream(parameterTypes)
                    .map(Class::getName)
                    .toArray(String[]::new);

            return result.getAllClasses().stream()
                    .filter(classInfo -> containsMatchingMethod(classInfo, methodName, parameterTypeNames))
                    .map(ClassInfo::getName)
                    .collect(Collectors.toList());
        }
    }

    /**
     * 校验类是否包含参数匹配的方法（辅助方法）
     */
    private static boolean containsMatchingMethod(ClassInfo classInfo, String methodName, String[] expectedParamTypes) {
        return classInfo.getMethodInfo(methodName).stream()
                .anyMatch(method -> {
                    String[] actualParamTypes = Arrays.stream(method.getParameterInfo())
                            .map(MethodParameterInfo::getTypeSignature)
                            .toArray(String[]::new);
                    return Arrays.equals(actualParamTypes, expectedParamTypes);
                });
    }

    /**
     * 匹配注解属性（辅助方法）
     */
    private static boolean matchAnnotationAttributes(ClassInfo classInfo,
                                                     Class<?> annotationClass,
                                                     Map<String, String> attributes) {
        AnnotationInfo annInfo = classInfo.getAnnotationInfo(annotationClass.getName());
        if (annInfo == null) {
            return false;
        }

        return attributes.entrySet().stream()
                .allMatch(entry -> {
                    Object value = annInfo.getParameterValues().getValue(entry.getKey());
                    return value != null && value.toString().equals(entry.getValue());
                });
    }

}